package br.com.roteador.persistence;

import java.io.Serializable;
import java.util.List;

import javax.inject.Inject;
import javax.persistence.EntityManager;
import javax.persistence.NoResultException;
import javax.persistence.NonUniqueResultException;
import javax.persistence.Query;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Root;

import org.apache.log4j.Logger;
import org.eclipse.persistence.config.CacheUsage;
import org.eclipse.persistence.config.HintValues;
import org.eclipse.persistence.config.QueryHints;

public abstract class AbstractDAO implements Serializable{
	/**
	 * 
	 */
	private static final long serialVersionUID = 8069295201136514745L;
	@Inject @DefaultEntityManager
	public EntityManager manager;
	
	protected Logger log = Logger.getLogger(this.getClass().getSimpleName());
	
	@SuppressWarnings("unchecked")
	public Long recuperaTotalAtivos(Class<?> clazz){

		CriteriaBuilder qb = manager.getCriteriaBuilder();
		CriteriaQuery<Long> cq = qb.createQuery(Long.class);
		Root<Object> tb = (Root<Object>) cq.from(clazz);
		qb.count(tb);
		cq.select(qb.count(tb));
		cq.where(qb.equal(tb.get("active"), 1));
		Query query = manager.createQuery(cq);
		return (Long) query.getSingleResult();
	}

	@SuppressWarnings("unchecked")
	public List<?> recuperaListaAtivos(Class<?> clazz, Integer quantidadeRegistros, Integer registroInicial){
		CriteriaBuilder qb = manager.getCriteriaBuilder();
		CriteriaQuery<Object> cq = (CriteriaQuery<Object>) qb.createQuery(clazz);
		Root<Object> tb = (Root<Object>) cq.from(clazz);
		cq.select(tb);
		cq.where(qb.equal(tb.get("active"), 1));
		Query query = manager.createQuery(cq);
		if(quantidadeRegistros > 0){
			query.setMaxResults(quantidadeRegistros);
		}
		query.setFirstResult(registroInicial);
		return query.getResultList();
	}
	
	public Query montaQuery(CriteriaQuery<?> criteriaQuery){
		Query query = manager.createQuery(criteriaQuery)
				.setHint(QueryHints.CACHE_USAGE, CacheUsage.DoNotCheckCache)
				.setHint(QueryHints.REFRESH, HintValues.TRUE);
		return query;
	}

	@SuppressWarnings("unchecked")
	public List<?> recuperaTodos(Class<?> clazz){
		CriteriaBuilder qb = manager.getCriteriaBuilder();
		CriteriaQuery<Object> cq = (CriteriaQuery<Object>) qb.createQuery(clazz);
		Root<Object> tb = (Root<Object>) cq.from(clazz);
		cq.select(tb);
		Query query = manager.createQuery(cq);
		return query.getResultList();
	}
	
	public Object recuperaRegistro(Query query){
		try {
			return query.getSingleResult();
		} catch (NoResultException e){
			log.info("NÃO ACHOU NENHUM REGISTRO ");
		} catch (NonUniqueResultException e) {
			log.info("ACHOU MAIS DE UM REGISTRO ");
			return query.getResultList().get(0);
		} catch (Exception e) {
			return null;
		}
		return null;
	}
	
	public List<?> recuperaLista(Query query){
		try {
			return query.getResultList();
		} catch (NoResultException e){
			log.info("NÃO ACHOU NENHUM REGISTRO");
		} catch (Exception e) {
			log.info("DEU RUIM");
			return null;
		}
		return null;
	}

	@RequerTransacao
	public void save(Object object) {
		manager.persist(object);
	}
	
	@RequerTransacao
	public void remove(Object object) {
		manager.remove(object);
		
	}

	@RequerTransacao
	public void update(Object object){
		manager.merge(object);
	}

	@RequerTransacao
	public void delete(Object object){
		manager.remove(object);
	}

	@RequerTransacao
	public void refresh(Object object) {
		manager.refresh(object);
	}

	public Object find(Class<?> clazz, Integer id){
		return manager.find(clazz, id);
	}

	public Object reference(Class<?> clazz, Integer id){
		return manager.getReference(clazz, id);
	}
	
	public void iniciaTransacao(){
		if(!manager.getTransaction().isActive()){
			manager.getTransaction().begin();
		}
	}
	
	public void fechaTransacao(){
		manager.getTransaction().commit();
	}

	public void detach(Object obj){
		manager.detach(obj);
	}
	
}